package net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators;

import net.lucode.hackware.magicindicator.FragmentContainerHelper;
import net.lucode.hackware.magicindicator.buildins.ArgbEvaluatorHolder;
import net.lucode.hackware.magicindicator.buildins.UIUtil;
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator;
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
import ohos.agp.animation.Animator;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

import java.util.Arrays;
import java.util.List;

/**
 * 直线viewpager指示器，带颜色渐变
 *
 * @since 2020-09-29
 */
public class LinePagerIndicator extends Component implements IPagerIndicator, Component.DrawTask {
    /**
     * 直线宽度 == title宽度 - 2 * mXOffset
     */
    public static final int MODE_MATCH_EDGE = 0;
    /**
     * 直线宽度 == title内容宽度 - 2 * mXOffset
     */
    public static final int MODE_WRAP_CONTENT = 1;
    /**
     * 直线宽度 == mLineWidth
     */
    public static final int MODE_EXACTLY = 2;

    private int mMode; // 默认为MODE_MATCH_EDGE模式

    // 控制动画
    private int mStartInterpolator = Animator.CurveType.LINEAR;
    private int mEndInterpolator = Animator.CurveType.LINEAR;

    private float mYOffset; // 相对于底部的偏移量，如果你想让直线位于title上方，设置它即可
    private float mLineHeight;
    private float mXOffset;
    private float mLineWidth;
    private float mRoundRadius;

    private Paint mPaint;
    private List<PositionData> mPositionDataList;
    private List<Integer> mColors;

    private RectFloat mLineRect = new RectFloat();

    /**
     * LinePagerIndicator
     *
     * @param context context
     */
    public LinePagerIndicator(Context context) {
        super(context);
        init(context);
    }

    private void init(Context context) {
        mPaint = new Paint();
        mPaint.setSubpixelAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mLineHeight = UIUtil.vp2px(context, 3);
        mLineWidth = UIUtil.vp2px(context, 10);
        addDrawTask(this);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.drawRoundRect(mLineRect, mRoundRadius, mRoundRadius, mPaint);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        if (mPositionDataList == null || mPositionDataList.isEmpty()) {
            return;
        }
        int nextPosition = position + 1;
        if (positionOffsetPixels < 0) {
            nextPosition = position - 1;
        }

        // 计算颜色
        if (mColors != null && mColors.size() > 0) {
            int currentColor = mColors.get(Math.abs(position) % mColors.size());
            int nextColor = mColors.get(Math.abs(nextPosition) % mColors.size());
            int color = ArgbEvaluatorHolder.eval(positionOffset, currentColor, nextColor);
            mPaint.setColor(new Color(color));
        }

        // 计算锚点位置
        PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position);
        PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, nextPosition);
        float leftX;
        float nextLeftX;
        float rightX;
        float nextRightX;
        if (mMode == MODE_MATCH_EDGE) {
            leftX = current.mLeft + mXOffset;
            nextLeftX = next.mLeft + mXOffset;
            rightX = current.mRight - mXOffset;
            nextRightX = next.mRight - mXOffset;
        } else if (mMode == MODE_WRAP_CONTENT) {
            leftX = current.mContentLeft + mXOffset;
            nextLeftX = next.mContentLeft + mXOffset;
            rightX = current.mContentRight - mXOffset;
            nextRightX = next.mContentRight - mXOffset;
        } else { // MODE_EXACTLY

            leftX = current.mLeft + (current.width() - mLineWidth) / 2;
            nextLeftX = next.mLeft + (next.width() - mLineWidth) / 2;
            rightX = current.mLeft + (current.width() + mLineWidth) / 2;
            nextRightX = next.mLeft + (next.width() + mLineWidth) / 2;
        }
        if (positionOffsetPixels < 0) {
            mLineRect.left = leftX
                    + (nextLeftX - leftX) * UIUtil.getInterpolation(mEndInterpolator, positionOffset);
            mLineRect.right = rightX
                    + (nextRightX - rightX) * UIUtil.getInterpolation(mStartInterpolator, positionOffset);
        } else {
            mLineRect.left = leftX
                    + (nextLeftX - leftX) * UIUtil.getInterpolation(mStartInterpolator, positionOffset);
            mLineRect.right = rightX
                    + (nextRightX - rightX) * UIUtil.getInterpolation(mEndInterpolator, positionOffset);
        }
        mLineRect.top = getHeight() - mLineHeight - mYOffset;
        mLineRect.bottom = getHeight() - mYOffset;
        addDrawTask(this);
    }

    @Override
    public void onPageSelected(int position) {
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

    @Override
    public void onPositionDataProvide(List<PositionData> dataList) {
        mPositionDataList = dataList;
    }

    /**
     * getYOffset
     *
     * @return mYOffset
     */
    public float getYOffset() {
        return mYOffset;
    }

    /**
     * setYOffset
     *
     * @param yOffset yOffset
     */
    public void setYOffset(float yOffset) {
        mYOffset = yOffset;
    }

    /**
     * getXOffset
     *
     * @return mXOffset
     */
    public float getXOffset() {
        return mXOffset;
    }

    /**
     * setXOffset
     *
     * @param xOffset xOffset
     */
    public void setXOffset(float xOffset) {
        mXOffset = xOffset;
    }

    /**
     * getLineHeight
     *
     * @return mLineHeight
     */
    public float getLineHeight() {
        return mLineHeight;
    }

    /**
     * setLineHeight
     *
     * @param lineHeight lineHeight
     */
    public void setLineHeight(float lineHeight) {
        mLineHeight = lineHeight;
    }

    /**
     * getLineWidth
     *
     * @return mLineWidth
     */
    public float getLineWidth() {
        return mLineWidth;
    }

    /**
     * setLineWidth
     *
     * @param lineWidth lineWidth
     */
    public void setLineWidth(float lineWidth) {
        mLineWidth = lineWidth;
    }

    /**
     * getRoundRadius
     *
     * @return mRoundRadius
     */
    public float getRoundRadius() {
        return mRoundRadius;
    }

    /**
     * setRoundRadius
     *
     * @param roundRadius roundRadius
     */
    public void setRoundRadius(float roundRadius) {
        mRoundRadius = roundRadius;
    }

    /**
     * getMode
     *
     * @return mMode
     */
    public int getMode() {
        return mMode;
    }

    /**
     * setMode
     *
     * @param mode mode
     */
    public void setMode(int mode) {
        if (mode == MODE_EXACTLY || mode == MODE_MATCH_EDGE || mode == MODE_WRAP_CONTENT) {
            mMode = mode;
        }
    }

    /**
     * getPaint
     *
     * @return mPaint
     */
    public Paint getPaint() {
        return mPaint;
    }

    /**
     * getColors
     *
     * @return mColors
     */
    public List<Integer> getColors() {
        return mColors;
    }

    /**
     * setColors
     *
     * @param colors colors
     */
    public void setColors(Integer... colors) {
        mColors = Arrays.asList(colors);
    }

    /**
     * getStartInterpolator
     *
     * @return mStartInterpolator
     */
    public int getStartInterpolator() {
        return mStartInterpolator;
    }

    /**
     * setStartInterpolator
     *
     * @param startInterpolator
     */
    public void setStartInterpolator(int startInterpolator) {
        mStartInterpolator = startInterpolator;
    }

    /**
     * getEndInterpolator
     *
     * @return mEndInterpolator
     */
    public int getEndInterpolator() {
        return mEndInterpolator;
    }

    /**
     * setEndInterpolator
     *
     * @param endInterpolator endInterpolator
     */
    public void setEndInterpolator(int endInterpolator) {
        mEndInterpolator = endInterpolator;
    }
}
